﻿using client.messengers.clients;
using common.libs;
using common.libs.extends;
using common.server;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace client.service.tcpforward
{
    public class TcpForwardHelper
    {
        public IPAddress IP { get; private set; }
        private readonly string configFileName = "config_tcp_forward.json";
        public List<TcpForwardRecordInfoBase> Mappings { get; set; } = new List<TcpForwardRecordInfoBase>();

        private readonly ITcpForwardServer tcpForwardServer;
        private readonly TcpForwardMessengerSender tcpForwardMessengerSender;
        private readonly IClientInfoCaching clientInfoCaching;

        NumberSpaceInt32 numberSpace = new NumberSpaceInt32();

        public TcpForwardHelper(ITcpForwardServer tcpForwardServer, TcpForwardMessengerSender tcpForwardMessengerSender,
            IClientInfoCaching clientInfoCaching)
        {
            this.tcpForwardServer = tcpForwardServer;
            this.tcpForwardMessengerSender = tcpForwardMessengerSender;
            this.clientInfoCaching = clientInfoCaching;

            ReadConfig();

            //A来了请求 ，转发到B，
            tcpForwardServer.OnRequest.Sub(OnRequest);
            //B接收到A的请求
            tcpForwardMessengerSender.OnData.Sub(OnData);
            tcpForwardServer.OnListeningChange.Sub((model) =>
            {
                TcpForwardRecordInfoBase mapping = Mappings.FirstOrDefault(c => c.SourcePort == model.SourcePort);
                if (mapping != null)
                {
                    mapping.Listening = model.Listening;
                }
            });

        }
        public void Start()
        {
            StartAll();
            Logger.Instance.Info("TCP转发服务已启动...");
        }

        private void OnRequest(TcpForwardRequestInfo arg)
        {
            if (arg.Connection == null)
            {
                tcpForwardServer.Fail(arg.Msg, "未选择转发对象，或者未与转发对象建立连接");
            }
            else
            {
                tcpForwardMessengerSender.Send(new SendArg
                {
                    Data = arg.Msg,
                    Connection = arg.Connection
                }).ConfigureAwait(false).GetAwaiter().GetResult();
            }
        }
        private void OnData(OnDataArg arg)
        {
            switch (arg.Data.Type)
            {
                //A收到了B的回复
                case TcpForwardTypes.RESPONSE:
                    tcpForwardServer.Response(arg.Data);
                    break;
                //A收到B的错误回复
                case TcpForwardTypes.FAIL:
                    tcpForwardServer.Fail(arg.Data);
                    break;
                default:
                    break;
            }
        }

        public string Del(int id)
        {
            TcpForwardRecordInfoBase map = Mappings.FirstOrDefault(c => c.ID == id);
            if (map != null)
            {
                Stop(map);
                Mappings.Remove(map);
            }
            return SaveConfig();
        }
        public string DelByPort(int port)
        {
            TcpForwardRecordInfoBase map = Mappings.FirstOrDefault(c => c.SourcePort == port);
            if (map != null)
            {
                Stop(map);
                Mappings.Remove(map);
            }
            return SaveConfig();
        }
        public string DelByGroup(string group)
        {
            var olds = Mappings.Where(c => c.Group == group).ToArray();
            for (int i = 0; i < olds.Length; i++)
            {
                Stop(olds[i]);
                Mappings.Remove(olds[i]);
            }
            return SaveConfig();
        }
        public TcpForwardRecordInfoBase GetByPort(int port)
        {
            return Mappings.FirstOrDefault(c => c.SourcePort == port);
        }

        public string Add(TcpForwardRecordInfoBase model)
        {
            TcpForwardRecordInfoBase portmap = Mappings.FirstOrDefault(c => c.SourcePort == model.SourcePort);
            if (model.ID == 0)
            {
                if (portmap != null)
                {
                    return "已存在相同源端口的记录";
                }
                model.ID = numberSpace.Get();
                Mappings.Add(model);
            }
            else
            {
                TcpForwardRecordInfoBase idmap = Mappings.FirstOrDefault(c => c.ID == model.ID);

                if (idmap.SourcePort == model.SourcePort && idmap.ID != portmap.ID)
                {
                    return "已存在相同源端口的记录";
                }

                idmap.SourceIp = model.SourceIp;
                idmap.SourcePort = model.SourcePort;
                idmap.TargetName = model.TargetName;
                idmap.TargetPort = model.TargetPort;
                idmap.AliveType = model.AliveType;
                idmap.TargetIp = model.TargetIp;
                idmap.Desc = model.Desc;
                idmap.Editable = model.Editable;
                idmap.Group = model.Group;
            }

            SaveConfig();

            return string.Empty;
        }
        public string Start(int id)
        {
            return Start(Mappings.FirstOrDefault(c => c.ID == id));
        }
        public string Start(TcpForwardRecordInfoBase model)
        {
            try
            {
                if (model != null)
                {
                    TcpForwardRecordInfo model2 = new()
                    {
                        AliveType = model.AliveType,
                        SourceIp = model.SourceIp,
                        SourcePort = model.SourcePort,
                        TargetIp = model.TargetIp,
                        TargetName = model.TargetName,
                        TargetPort = model.TargetPort,
                        Desc = model.Desc,
                        Editable = model.Editable
                    };

                    model2.Client = clientInfoCaching.All().FirstOrDefault(c => c.Name == model.TargetName);
                    if (model2.Client == null)
                    {
                        model2.Client = new ClientInfo { Name = model.TargetName };
                    }
                    tcpForwardServer.Start(model2);
                    SaveConfig();
                }
                return string.Empty;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        public void StartAll()
        {
            StopAll();
            Mappings.ForEach(c =>
            {
                Start(c);
            });
        }
        public void Stop(int id)
        {
            Stop(Mappings.FirstOrDefault(c => c.ID == id));
        }
        public void Stop(TcpForwardRecordInfoBase model)
        {
            tcpForwardServer.Stop(model.SourcePort);
            SaveConfig();
        }
        public void StopAll()
        {
            Mappings.ForEach(c =>
            {
                tcpForwardServer.Stop(c.SourcePort);
            });
            SaveConfig();
        }

        private void ReadConfig()
        {
            if (File.Exists(configFileName))
            {
                ConfigFileModel config = File.ReadAllText(configFileName).DeJson<ConfigFileModel>();
                if (config != null)
                {
                    config.Mappings.ForEach(c =>
                    {
                        c.Listening = false;
                    });
                    Mappings = config.Mappings;

                    numberSpace.Reset(Mappings.Count == 0 ? 1 : Mappings.Max(c => c.ID));
                }
            }
        }
        private string SaveConfig()
        {
            try
            {

                File.WriteAllText(configFileName, new ConfigFileModel
                {
                    Mappings = Mappings
                }.ToJson());
                return string.Empty;
            }
            catch (Exception ex)
            {
                return (ex.Message);
            }
        }
    }

    public class ConfigFileModel
    {
        public ConfigFileModel() { }
        public List<TcpForwardRecordInfoBase> Mappings { get; set; } = new List<TcpForwardRecordInfoBase>();
    }

}